/**
   Demo of writing a custom JSONMessage.Request.prototype.postBackend().
   This one uses the Rhino JavaScript engine, which allows us to use
   Java functionality for the network support.

   Mis-features:

   - Only POST is supported by this implementation. Adding GET
   shouldn't be too hard, but i discourage using GET for JSON
   requests, as it clogs up the server's apache logs.

   - It does not support asynchronous operation. It shouldn't be too
   hard to add via a new Java thread, though handling timeouts
   accurately might be complicated by blocking read operations unless
   maybe there's another thread watching the i/o thread. Even then,
   we might not have a way of cancelling a blocking i/o operation.

   - It is a quick hack and only lightly tested.
*/

// Import JSONMessage-required scripts. Adjust the paths as needed!
(function() {
    var includes = ['json2.js',
                    'JSONable.inc.js',
                    'extendClass.js',
                    'JSONMessage.inc.js'
                    ];
    for( var i in includes ) {
        load(includes[i]);
    }
})();

JSONMessage.rhino = {
    /**
        Fetches raw JSONMessage.Response JSON code.

        req is the Request object. args are the normalized
        post() parameters, which must be fully populated by
        the caller. req.postOptions() is ignored in favour
        of the args argument.

        Limitations vis-a-vis the JSONMessage.request.post() interface:


        - Does not support asynchronous requests. Handling this requires
         being able to cancel running Java threads.

         - The timeout option is not honored because we have no way of
         interrupting a read() request to honor the timeout. We do not
         check for a timeout after reading each line because most
         server-delivered JSON is delivered without extra spacing, taking
         only one line.

         - Does not honor the jsonpCallback option because it is not expected
         that a Rhino-based client will ever have to deal with Same Origin Policy
         limitations.
     */
    fetchMessageJSON:function(req,args) {
        var url = new java.net.URL( args.url );
        var con = url.openConnection();
        con.setDoOutput( true );
        var IO = new JavaImporter(java.io);
        var wr = new IO.OutputStreamWriter(con.getOutputStream());
        (function() {
            var enc = JSONMessage.Request.options.requestKey
                +'='+(encodeURI(req.toJSON(false)).replace(/%20/g,'+'));
            wr.write(enc);
            wr.flush();
        })();
        var rd = new IO.BufferedReader(new IO.InputStreamReader(con.getInputStream()));
        var line;
        var json = [];
        while ((line = rd.readLine()) != null) {
            json.push(line);
        }
        try { wr.close(); } catch(e) { /*ignore*/}
        try { rd.close(); } catch(e) { /*ignore*/}
        return json.join('');
    }
};
/**
    A JSONMessage.Request.postBackend() implementation which uses
    the Rhino JS engine to post a request.

    It conforms to the JSONMessage.Request.postBackend() interface.

    Limitations: see JSONMessage.rhino.fetchMessageJSON()
*/
JSONMessage.Request.postImpl.concrete.rhinoJava = function(args) {
    var json;
    var request = this;
    var isError = false;
    try {
        json = JSONMessage.rhino.fetchMessageJSON(request,args);
        if( null == json ) {
            throw new Error("Fetched message succeeded but returned no data!");
        }
    }
    catch(e) {
        isError = e;
    }
    if( ! isError ) {
        try {
            JSONMessage.Request.postImpl.onPostSuccess( this, json, args );
        }
        catch(e) {
            isError = e;
            if( !args.errorMessage ) {
                args.errorMessage = "Exception from the onResponse() callback: "+e.toString();
            }
        }
    }
    if( isError ) {
        if( !args.errorMessage ) {
            args.errorMessage = "Exception while sending request: "+isError.toString();
        }
        try {
            JSONMessage.Request.postImpl.onPostError( request, args );
        }
        catch(e) {/*ignore*/}
    }
    return undefined;
};

/************************************************************************
Configure JSONMessage.Request to use our implementation...
 ************************************************************************/
JSONMessage.Request.options.ajax.url =
    // public demo site:
    'http://fossil.wanderinghorse.net/demos/JSONMessage/lib/JSONMessage/JSONRequest-dispatch.php'
    // local dev server:
    //'http://jsonmessage/lib/JSONMessage/JSONRequest-dispatch.php'
    // Another local dev server...
    //'http://localhost:8080/JSONMessage/dispatch'
    ;

// Default onError() handler:
JSONMessage.Request.options.ajax.onError = function(req,opt) {
    print("REQUEST ERROR:\n"+opt.errorMessage);
    print("Connection parameters were:\n",JSON.stringify(opt,null,4));
};

// Default beforePost() handler:
JSONMessage.Request.options.ajax.beforePost = function(req,opt) {
    print("POSTing '"+req.type()+"' request to",opt.url,'...');
};

// Default onResponse() handler:
JSONMessage.Request.options.ajax.onResponse = function(resp,req) {
    print("GOT RESPONSE: ",resp.toJSON());
};

// Install the rhino-based back-end as the default post() implementation:
JSONMessage.Request.prototype.postBackend = JSONMessage.Request.postImpl.concrete.rhinoJava;


// Now let's see if it works...
function demoRhinoRequests() {
    // Call as (ConstructorFunction, {payload})
    // or ({core request options}).
    function post(klass,payload) {
        if(1==arguments.length) {
            (new JSONMessage.Request(klass)).post();
        }
        else {
            (new klass()).payload(payload).post();
        }
    }
    post( JSONMessage.Request.Ping, {reminderToSelf:"hi, world!"} );
    post( {type:'ChuckNorris'} );
}

demoRhinoRequests();
